#include "../include/debug.h"

std::vector<dword> breakpoints;

extern qword iregs[128];
extern float fregs[64];
extern double dregs[64];
extern byte codes[0x1000000];
extern byte datas[0x1000000];

void addBreak(dword position)
{
	breakpoints.push_back(position);
}
void removeBreak(dword position)
{
	if (std::find(breakpoints.begin(), breakpoints.end(), position) != breakpoints.end())
		breakpoints.erase(std::find(breakpoints.begin(), breakpoints.end(), position));
}
void viewBreak()
{
	for (int i = 0; i < breakpoints.size(); i++)
		printf("Breakpoint %d: 0x%08x\n", i, breakpoints[i]);
}
void print()
{
	std::string type, value;
	std::cin >> type >> value;
	dword address = std::stoi(value, nullptr, 16);
	if (type == "codes")
	{
		for (int i = 0; i < 128; i++)
		{
			if ((i % 16) == 0)
				printf("0x%08x : ", (address & 0xffff00) + i);
			printf("0x%02x ", codes[(address & 0xffff00) + i]);
			if ((i % 8) == 7)
				printf(" ");
			if ((i % 16) == 15)
				printf("\n");
		}
	}
	else if (type == "datas")
	{
		for (int i = 0; i < 128; i++)
		{
			if ((i % 16) == 0)
				printf("0x%08x : ", (address & 0xffff00) + i);
			printf("0x%02x ", datas[(address & 0xffff00) + i]);
			if ((i % 8) == 7)
				printf(" ");
			if ((i % 16) == 15)
				printf("\n");
		}
	}
	else if (type == "Intregs")
		printf("Int Register %d : 0x%016llx\n", address & 0x7f, iregs[address & 0x7f]);
	else if (type == "Floatregs")
		printf("Float Register %d : %f\n", address & 0x3f, fregs[address & 0x3f]);
	else if (type == "Doubleregs")
		printf("Double Register %d : %lf\n", address & 0x3f, dregs[address & 0x3f]);
	else if (type == "Help")
		std::cout << "Type \"help\" to view all commands.\n"
				  << "Type \"codes\" to view code block.\n"
				  << "Type \"datas\" to view data block.\n"
				  << "Type \"Intregs\" to view int register.\n"
				  << "Type \"Floatregs\" to view float register.\n"
				  << "Type \"Doubleregs\" to view double register.\n";
	else
		printf("Invalid value type.\n");
}
void execute()
{
	if (!(iregs[Flag] & RUNNING))
	{
		std::cout << "Program has stopped.\n";
		return;
	}
	while (iregs[Flag] & RUNNING)
		selector(loader());
}
void step()
{
	if (!(iregs[Flag] & RUNNING))
	{
		std::cout << "Program has stopped.\n";
		return;
	}
	selector(loader());
}
void breaker()
{
	if (!(iregs[Flag] & RUNNING))
	{
		std::cout << "Program has stopped.\n";
		return;
	}
	while (iregs[Flag] & RUNNING)
	{
		selector(loader());
		if (std::find(breakpoints.begin(), breakpoints.end(), iregs[Code]) != breakpoints.end())
			return;
	}
}
#ifdef __debug__
void dmain()
{
	printf("System now running at debug mode.\n");
	char option = '\x20';
	std::string value;
	while (option != 'q')
	{
		printf("Debugger>");
		std::cin >> option;
		switch (option)
		{
		case 'q':
			printf("Exit.\n");
			exit(0);
			break;
		case 'b':
			std::cin >> value;
			addBreak(std::stoi(value, nullptr, 16));
			break;
		case 'd':
			std::cin >> value;
			removeBreak(std::stoi(value, nullptr, 16));
			break;
		case 'v':
			viewBreak();
			break;
		case 'p':
			print();
			break;
		case 'n':
			getchar();
			step();
			break;
		case 'r':
			getchar();
			execute();
			break;
		case 't':
			getchar();
			breaker();
			break;
		case 'h':
		case '?':
			std::cout << "Print \'h\' to show the help message.\n"
					  << "b:add a breakpoint.\n"
					  << "d:delete a breakpoint.\n"
					  << "v:check all breakpoints.\n"
					  << "p:print the value of a register.\n"
					  << "n:step one instruction.\n"
					  << "r:execute the program.\n"
					  << "t:break the program.\n"
					  << "h,?:show the help message.\n"
					  << "q:quit debugger.\n";
			break;
		default:
			printf("Invalid option.\n");
			break;
		}
	}
}
#elif __graph__
void dmain(int argc, char **argv)
{
}
#else
void dmain(int argc, char **argv)
{
	if (argc < 1)
}
#endif